/**
   @file  protocol.h
   @brief ENet protocol
 */
#ifndef __ENET_PROTOCOL_H__
#define __ENET_PROTOCOL_H__

#include "enet/types.h"

enum
{
    ENET_PROTOCOL_MINIMUM_MTU = 576,
    ENET_PROTOCOL_MAXIMUM_MTU = 4096,
    ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32,
    ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096,
    ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 32768,
    ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1,
    ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255,
    ENET_PROTOCOL_MAXIMUM_PEER_ID = 0x7FFF
};

typedef enum
{
    ENET_PROTOCOL_COMMAND_NONE = 0,
    ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1,
    ENET_PROTOCOL_COMMAND_CONNECT = 2,
    ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3,
    ENET_PROTOCOL_COMMAND_DISCONNECT = 4,
    ENET_PROTOCOL_COMMAND_PING = 5,
    ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6,
    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7,
    ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8,
    ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9,
    ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10,
    ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11,
    ENET_PROTOCOL_COMMAND_COUNT = 12,

    ENET_PROTOCOL_COMMAND_MASK = 0x0F
} ENetProtocolCommand;

typedef enum
{
    ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7),
    ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6),

    ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15),
    ENET_PROTOCOL_HEADER_FLAG_MASK = 0x8000
} ENetProtocolFlag;

typedef struct
{
    enet_uint32 checksum;
    enet_uint16 peerID;
    enet_uint16 sentTime;
} ENetProtocolHeader;

typedef struct
{
    enet_uint8 command;
    enet_uint8 channelID;
    enet_uint16 reliableSequenceNumber;
} ENetProtocolCommandHeader;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 receivedReliableSequenceNumber;
    enet_uint16 receivedSentTime;
} ENetProtocolAcknowledge;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 outgoingPeerID;
    enet_uint16 mtu;
    enet_uint32 windowSize;
    enet_uint32 channelCount;
    enet_uint32 incomingBandwidth;
    enet_uint32 outgoingBandwidth;
    enet_uint32 packetThrottleInterval;
    enet_uint32 packetThrottleAcceleration;
    enet_uint32 packetThrottleDeceleration;
    enet_uint32 sessionID;
} ENetProtocolConnect;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 outgoingPeerID;
    enet_uint16 mtu;
    enet_uint32 windowSize;
    enet_uint32 channelCount;
    enet_uint32 incomingBandwidth;
    enet_uint32 outgoingBandwidth;
    enet_uint32 packetThrottleInterval;
    enet_uint32 packetThrottleAcceleration;
    enet_uint32 packetThrottleDeceleration;
} ENetProtocolVerifyConnect;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint32 incomingBandwidth;
    enet_uint32 outgoingBandwidth;
} ENetProtocolBandwidthLimit;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint32 packetThrottleInterval;
    enet_uint32 packetThrottleAcceleration;
    enet_uint32 packetThrottleDeceleration;
} ENetProtocolThrottleConfigure;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint32 data;
} ENetProtocolDisconnect;

typedef struct
{
    ENetProtocolCommandHeader header;
} ENetProtocolPing;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 dataLength;
} ENetProtocolSendReliable;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 unreliableSequenceNumber;
    enet_uint16 dataLength;
} ENetProtocolSendUnreliable;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 unsequencedGroup;
    enet_uint16 dataLength;
} ENetProtocolSendUnsequenced;

typedef struct
{
    ENetProtocolCommandHeader header;
    enet_uint16 startSequenceNumber;
    enet_uint16 dataLength;
    enet_uint32 fragmentCount;
    enet_uint32 fragmentNumber;
    enet_uint32 totalLength;
    enet_uint32 fragmentOffset;
} ENetProtocolSendFragment;

typedef union
{
    ENetProtocolCommandHeader header;
    ENetProtocolAcknowledge acknowledge;
    ENetProtocolConnect connect;
    ENetProtocolVerifyConnect verifyConnect;
    ENetProtocolDisconnect disconnect;
    ENetProtocolPing ping;
    ENetProtocolSendReliable sendReliable;
    ENetProtocolSendUnreliable sendUnreliable;
    ENetProtocolSendUnsequenced sendUnsequenced;
    ENetProtocolSendFragment sendFragment;
    ENetProtocolBandwidthLimit bandwidthLimit;
    ENetProtocolThrottleConfigure throttleConfigure;
} ENetProtocol;

#endif /* __ENET_PROTOCOL_H__ */